/* 
 * File:   ProcessMessage.cpp
 * Author: dell
 * 
 * Created on 2012年11月26日, 下午5:32
 */

#include "ProcessMessage.h"
#include <sys/msg.h>
#include <string>
#include <fcntl.h>
#include <stdio.h>
#include <cerrno>
#include <signal.h>

//#include <event.h>
//#include <evhttp/Timer.h>

using namespace std;

namespace Rapid{
    ProcessMessage::ProcessMessage():msdid(-1) {

    }


    ProcessMessage::~ProcessMessage() {
        close();
    }

    bool ProcessMessage::open(const char* homedir){
        if(msdid >= 0){
            return true;
        }
        string keyfilename = string(homedir).append("conf/msgkey.dat");
        
        bool keyfileexist = ::access(keyfilename.c_str(), F_OK) == 0;
        
        FD fd = ::open(keyfilename.c_str(), O_CREAT | O_RDWR | O_SYNC, S_IRWXU | S_IRWXG | S_IRWXO);
        if(fd < 0){
            LOG_ERROR("open %s file error, errno:%d", keyfilename.c_str(), errno);
            return false;
        }
        
        
        key_t key = 0;
        char keybuff[32];
        if(keyfileexist){
            ssize_t rsize = ::read(fd, keybuff, 32);
            if(rsize < 0){
                LOG_ERROR("read %s file error, errno:%d", keyfilename.c_str(), errno);
                ::close(fd);
                return false;
            }
            
            keybuff[rsize] = 0;
            key = atol(keybuff);
            LOG_DEBUG("2 key:%d", key);
        }
        
        if(key == 0){
           //生成key并写入文件   
           key = ftok(keyfilename.c_str(), getpid());
           sprintf(keybuff, "%d", key);
            
            char* bufpt = &keybuff[0];
            int len = strlen(keybuff);
            ssize_t wsize = -1;
            do{
                wsize = ::write(fd, bufpt, len);
                if(wsize == len){
                    break;
                }
                if(wsize < 0){
                    if(ERRNO_IS_AGAIN()){
                        continue;
                    }
                    LOG_ERROR("write %s file error, errno:%d", keyfilename.c_str(), errno);
                    break;
                }else{
                    len -= wsize;
                    bufpt += wsize;
                }
            }while(1);
            
            LOG_DEBUG("1 key:%d", key);

        }
        ::close(fd);    
        LOG_DEBUG("key:%d", key);
        
        return open(key);
        
    }

    bool ProcessMessage::open(key_t key){
        if(msdid >= 0){
            return true;
        }
        msdid = msgget(key, IPC_CREAT | 666);
        if(msdid < 0){
            LOG_ERROR("open msg queue error, errno:%d, %s", errno, ((errno==ENOSPC)?"The message queue, but has reached the limit of the system":""));
            return false;
        }
        
        return true;
    }

    bool ProcessMessage::isClosed(){
        return msdid < 0;
    }

    void ProcessMessage::close(){
        if(msdid >= 0){
            LOG_DEBUG("");
            msgctl(msdid, IPC_RMID, NULL);
            msdid = -1;
        }
    }

    bool ProcessMessage::send(const void* data, size_t size){
        if(msdid < 0){
            return false;
        }
        LOG_DEBUG("send msg");
        return msgsnd(msdid, data, size, 0) >= 0;
    }

    ssize_t ProcessMessage::receive(void* data, size_t size){
        return msgrcv(msdid, data, size, 0, IPC_NOWAIT);
    }

//bool ProcessMessage::startReceive(){
//    if(msdid < 0)return false;
//    start(0, 5);
//    return true;
//}

//bool ProcessMessage::onTimerEvent(const TimerEvent* e){
//    if(msdid < 0)return true;
//    
//    char buf[1024];
//    ssize_t rsize = msgrcv(msdid, buf, 1024, 0, IPC_NOWAIT);
//    LOG_DEBUG("rsize:%d", rsize);
//}


//void ProcessMessage::readCallback(ev::io& io, int revents){
//    LOG_DEBUG("");
//    
//}

}
